#ifndef SDFS_CONFIGURATION
#define SDFS_CONFIGURATION

#include <muduo/base/Types.h>

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>  // snprintf
#include <strings.h>  // bzero
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/stat.h>

#include <boost/shared_ptr.hpp>

#include <sdfs/common/md5.h>

using namespace boost;

#ifndef MAX_PATH
#define MAX_PATH 255
#endif

#ifndef INET_ADDRSTRLEN
#define INET_ADDRSTRLEN 22
#endif

template <typename T>
struct SortFunctor
{
  bool operator()(const boost::shared_ptr<T>& p1,const boost::shared_ptr<T>& p2)
  {
    return(*p1 < *p2);
  }
};

inline uint32_t networkToHost32(uint32_t net32)
{
  return be32toh(net32);
}

inline uint16_t networkToHost16(uint16_t net16)
{
  return be16toh(net16);
}


namespace sdfs
{
class ToolKit
{
public:
	template <typename T>
	static boost::shared_ptr<T> binaryFind(const std::vector< shared_ptr<T> >& array, const T& target)
	{
		int low = 0;
		int high = array.size()-1;
		
		while (low <= high)
		{
			int mid = ( low + high ) / 2;
			if (target < *(array[mid]))
				high = mid - 1;
			else if (*(array[mid]) < target)
				low = mid + 1;
			else //find the target
				return array[mid];
		}
		boost::shared_ptr<T> ptr;
		return ptr;
	}

	static bool getCfgFileName(muduo::string& paraStr_CfgFileName, const muduo::string& filename)  
	{  
		paraStr_CfgFileName.clear() ;  
		char szWorkDir[MAX_PATH] = {0} ;  
		if(!getcwd(szWorkDir, 260))  
		{  
			return false ;  
		}  
	  
		paraStr_CfgFileName = szWorkDir ;  
		paraStr_CfgFileName.append("/") ;  
		paraStr_CfgFileName.append(filename) ;  
	  
		return true ;  
	}

	static long getFileSize(const char *filename)
	{
		struct stat buf;
		if(::stat(filename, &buf)<0)
		{
			return 0;
		}
		return (long)buf.st_size;
	}



	static bool equels(const char* str1, const char* str2)
	{
		const char* p1 = str1;
		const char* p2 = str2;
		while(*p1 == *p2)
		{
			if(*p1 == '\0')
				return true;
			p1++;
			p2++;
		}
		return false;
	}

	static int toPort(const struct sockaddr_in& addr)
	{
		return networkToHost16(addr.sin_port);
	}

	static muduo::string fileMd5(const muduo::string& file)
	{
		ifstream in(file.c_str(), std::ios::binary);
		if (!in) {
			return "";
		}
		MD5 md5;
		std::streamsize length;
		char buffer[1024];
		while (!in.eof()) {
			in.read(buffer, 1024);
			length = in.gcount();
			if (length > 0) {
				md5.update(buffer, length);
			}
		}
		in.close();
		return md5.toString().c_str();
	}

	static void toIpPort(char* buf, size_t size,
                       const struct sockaddr_in& addr)
	{
	  char host[INET_ADDRSTRLEN] = "INVALID";
	  toIp(host, sizeof host, addr);
	  uint16_t port = networkToHost16(addr.sin_port);
	  snprintf(buf, size, "%s:%u", host, port);
	}

	static void toIp(char* buf, size_t size,
	                   const struct sockaddr_in& addr)
	{
	  assert(size >= INET_ADDRSTRLEN);
	  ::inet_ntop(AF_INET, &addr.sin_addr, buf, static_cast<socklen_t>(size));
	}

/*	static muduo::net::InetAddress& fillInetAddress(const char* ip, int port)
	{
		sockaddr_in sockaddr;
		sockaddr.sin_family = AF_INET;
		sockaddr.sin_port = htobe16(port);
		if (::inet_pton(AF_INET, ip, &sockaddr.sin_addr) <= 0)
		{
		    LOG_SYSERR << "sockets::fromIpPort";
		}
		muduo::net::InetAddress addr(sockaddr);
		return addr;
	}
*/
};
}
#endif
